<?php
declare (strict_types=1);

namespace app\course\logic\coupon;

use app\common\exception\LogicException;
use app\common\helper\util\SnowFlake;
use app\course\model\base\{Course, CourseStudent};
use app\course\model\coupon\{Coupon as CouponModel, CouponUser};
use app\course\model\payment\{PaymentOrder as PO, PaymentOrderItem as POI, PaymentOrderItemCoupon as POIC};
use app\user\logic\user\TicketCoupon;
use Exception;
use think\Collection;
use think\db\BaseQuery;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

/**
 * 卡券逻辑类
 * @method join(string $string, string $string1)
 * @method canDerive($id)
 * @method buildSql()
 */
class Coupon extends CouponModel
{

    /**
     * 获取课程可领取卡券
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-26
     */
    public function getCourseCoupon($param): array
    {
        // 验证数据
        $this->getValidate()->scene('course')->failException()->check($param);
        // 参数
        $course_id = $param['course_id'];
        $group     = intval(isset($param['group']) ?? 0);

        try {
            return $this->getCourseCouponWithParam($course_id, $group);
        } catch (DataNotFoundException|ModelNotFoundException|DbException $e) {
            return [];
        }
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function getCourseCouponWithParam($course_id = 0, $group = false): array
    {
        $course = app(Course::class)->findOrEmpty($course_id);
        if ($course->isEmpty()) return [];

        $map1 = [
            ['coupon_type', '=', 1],
            ['maxprice', '<=', $course->price],
            ['mhm_id', '=', $course->mhm_id],
        ];
        $map2 = [
            ['coupon_type', '=', 2],
            ['mhm_id', '=', $course->mhm_id],
        ];
        $map3 = [
            ['coupon_type', '=', 3],
            ['course_id', '=', $course_id],
            ['mhm_id', '=', $course->mhm_id],
        ];

        if ($group) {
            $coupon = [
                ['coupon_type_text' => '优惠券', 'list' => $this->getCourseCouponByMap($map1)],
                ['coupon_type_text' => '打折卡', 'list' => $this->getCourseCouponByMap($map2)],
                ['coupon_type_text' => '课程卡', 'list' => $this->getCourseCouponByMap($map3)],
            ];
        } else {
            $_coupon = $this->with(['user_has'])->scope(['canDerive'])->where(function ($query) use ($map1, $map2, $map3) {
                $query->whereOr([$map1, $map2, $map3]);
            })->select()->each(function ($item) {
                $has = $item['user_has'];
                unset($item['user_has']);
                $item['user_has'] = $has ? 1 : 0;
                $item['user_use'] = $has['status'] ? 1 : 0;
                return $item;
            });

            $coupon = [];
            foreach ($_coupon as $item) {
                if (!$item['user_has']) $coupon[] = $item;
            }
        }
        return $coupon;
    }

    // 根据条件查询课程可领取卡券

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function getCourseCouponByMap($map): array
    {
        $_coupon = $this->with(['user_has'])->scope(['canDerive'])->where($map)->select()->each(function ($item) {
            $has = $item['user_has'];
            unset($item['user_has']);
            $item['user_has'] = $has ? 1 : 0;
            $item['user_use'] = $has['status'] ? 1 : 0;
            return $item;
        });

        $coupon = [];
        foreach ($_coupon as $item) {
            if (!$item['user_has']) $coupon[] = $item;
        }
        return $coupon;
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function getCourseRecommendCoupon($course_id = 0, $limit = 0, $detail = false): array
    {
        $course = app(Course::class)->findOrEmpty($course_id);
        if ($course->isEmpty()) {
            return [];
        }

        $map = [
            [
                ['coupon_type', '=', 1],
                ['maxprice', '<=', $course->price],
                ['mhm_id', '=', $course->mhm_id],
            ],
            [
                ['coupon_type', '=', 2],
                ['mhm_id', '=', $course->mhm_id],
            ],
            [
                ['coupon_type', '=', 3],
                ['course_id', '=', $course_id],
                ['mhm_id', '=', $course->mhm_id],
            ]
        ];

        $coupon = $this->with(['user_has'])->scope(['canDerive'])->where(function ($query) use ($map) {
            $query->whereOr($map);
        })->limit($limit)->select()->each(function ($item) {
            $has = $item['user_has'];
            unset($item['user_has']);
            $item['user_has'] = $has ? 1 : 0;
            return $item;
        });

        if (!$detail) {
            $new = [];
            foreach ($coupon as $v) {
                if (!$v->user_has) {
                    switch ($v->coupon_type) {
                        case 1:
                            $new[] = '满' . floatval($v->maxprice) . '减' . floatval($v->price);
                            break;

                        case 2:
                            $new[] = floatval($v->discount) . '折卡';
                            break;

                        case 3:
                            $new[] = '课程卡';
                            break;
                    }
                }
            }
            return $new;
        }

        return $coupon->toArray();
    }

    /**
     * 获取用户已领取的针对课程可用的卡券
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-26
     *
     * @param $param
     * @return Coupon[]|array|array[]|Collection [type]                      [description]
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getUserCourseCoupon($param)
    {
        // 验证数据
        $this->getValidate()->scene('course')->failException()->check($param);
        // 参数
        $course_id = $param['course_id'];
        $group     = intval(isset($param['group']) ?? 0);
        //
        $course = app(Course::class)->findOrEmpty($course_id);
        //
        $coupons = app(CouponUser::class)->mhmUserCanUse($course->mhm_id)->select();
        // return $coupons;
        $ids = array_column($coupons->toArray(), 'coupon_id');

        $ticket    = app(CouponUser::class)->mhmUserCanUse($course->mhm_id)->whereNotNull('ticket_id')->whereRaw('end_time is null or end_time > ' . time())->select();
        $ticketIds = array_column($ticket->toArray(), 'ticket_id');
        $map1      = [
            ['coupon_type', '=', 1],
            ['maxprice', '<=', $course->user_price],
        ];
        $map2      = [
            ['coupon_type', '=', 2],
        ];
        $map3      = [
            ['coupon_type', '=', 3],
            ['course_id', '=', $course_id],
        ];
        if ($group) {
            return [
                ['coupon_type_text' => '优惠券', 'list' => $this->getUserCourseCouponByMap($map1, $ids, $ticketIds)],
                ['coupon_type_text' => '打折卡', 'list' => $this->getUserCourseCouponByMap($map2, $ids, $ticketIds)],
                ['coupon_type_text' => '课程卡', 'list' => $this->getUserCourseCouponByMap($map3, $ids)],
            ];
        } else {
            $coupon = $this->scope(['hasDerived'])->where('id', 'IN', $ids)->where(function ($query) use ($map1, $map2, $map3) {
                $query->whereOr([$map1, $map2, $map3]);
            })->select()->toArray();

            if (!count($ticketIds)) return $coupon;

            $market = app(TicketCoupon::class)->with(['mhm_title', 'use_time'])->where('id', 'IN', $ticketIds)->where(function ($query) use ($map1, $map2) {
                $query->whereOr([$map1, $map2]);
            })->select()->toArray();

            return array_merge($coupon, $market);
        }
    }

    // 根据条件查询用户已领取的针对课程可用的卡券

    /**
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws DataNotFoundException
     */
    public function getUserCourseCouponByMap($map, $ids, $ticketIds = [], $type = 0)
    {
        // 卡券
        $coupon = $this->scope(['hasDerived'])->where('id', 'IN', $ids)->where($map)->select()->toArray();
        // 活动券
        if (!count($ticketIds)) return $coupon;
        // if (!count($ticketIds) || !$type) return $coupon;

        $market = app(TicketCoupon::class)->with(['mhm_title', 'use_time'])->where('id', 'IN', $ticketIds)->where($map)->select()->toArray();

        return array_merge($coupon, $market);
    }

    /**
     * 获取机构可领取卡券
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-26
     */
    public function getSchoolCoupon($param)
    {
        // 验证数据
        $this->getValidate()->scene('school')->failException()->check($param);
        // 参数
        $mhm_id = $param['mhm_id'];
        $group  = intval(isset($param['group']) ?? 0);
        if ($group) {
            $coupon = [
                ['coupon_type_text' => '优惠券', 'list' => $this->getMhmDeriveCoupon($mhm_id, '1')],
                ['coupon_type_text' => '打折卡', 'list' => $this->getMhmDeriveCoupon($mhm_id, '2')],
                ['coupon_type_text' => '课程卡', 'list' => $this->getMhmDeriveCoupon($mhm_id, '3')],
            ];
        } else {
            $coupon = $this->getMhmDeriveCoupon($mhm_id, '1,2,3');
        }

        return $coupon;
    }

    /**
     * 根据类型获取机构可领取的卡券
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-28
     */
    protected function getMhmDeriveCoupon($mhm_id, $type)
    {
        try {
            return $this->scope(['canDerive'])->scope('mhmDeriveCoupon', $mhm_id, $type)->with(['user_has'])
                // ->buildSql();
                ->select()->each(function ($item) {
                    $has = $item['user_has'];
                    unset($item['user_has']);
                    $item['user_has'] = $has ? 1 : 0;
                    $item['user_use'] = $has['status'] ? 1 : 0;
                    return $item;
                })->toArray();
        } catch (DataNotFoundException|ModelNotFoundException|DbException $e) {
            return [];
        }
    }

    /**
     * 获取用户领取的对应机构的可用卡券列表
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-23
     *
     * @param    [type]     $mhm_id      [机构ID]
     * @param    [type]     $total_price [满减价格]
     */
    public function getUserSchoolCoupon($param): array
    {
        // 验证数据
        $this->getValidate()->scene('user_school')->failException()->check($param);
        $mhm_id = $param['mhm_id'];
        $price  = $param['price'];
        $group  = intval(isset($param['group']) ?? 0);
        if ($group) {
            $list = [
                ['useful' => 1, 'coupon_type_text' => '优惠券', 'list' => $this->getUserMhmCoupon($mhm_id, $price, 1)],
                ['useful' => 1, 'coupon_type_text' => '打折卡', 'list' => $this->getUserMhmCoupon($mhm_id, $price, 2)],
                ['useful' => 0, 'coupon_type_text' => '不可用', 'list' => $this->getUserMhmCoupon($mhm_id, $price, 1, 0)],
            ];
        } else {
            $list = $this->getUserMhmCoupon($mhm_id, $price, '1,2,3');
        }

        return $list;
    }

    /**
     * 获取用户领取的可用的对应机构的可用卡券列表
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-28
     */
    protected function getUserMhmCoupon($mhm_id, $price, $type, $useful = 1)
    {
        $where = app(CouponUser::class)->mhmUserCanUse($mhm_id);
        $mstr  = $useful ? '<=' : '>=';

        $coupon = $this->hasWhere('couponUser', $where)->couponType($type)->where('use_stime', '<', time())->where('use_etime', '>', time())->where('maxprice', $mstr, $price)->whereNull('Coupon.delete_time')->select()->toArray();
        //
        $ticket = app(CouponUser::class)->mhmUserCanUse($mhm_id)->whereNotNull('ticket_id')->whereRaw('end_time is null or end_time > ' . time())->select();
        // 可使用活动券
        $ticketIds = array_column($ticket->toArray(), 'ticket_id');
        // 无活动券返回卡券
        if (!count($ticketIds)) return $coupon;
        // halt($ticketIds);
        // 获取活动券
        $market = app(TicketCoupon::class)->with(['mhm_title', 'use_time'])->whereIn('id', $ticketIds)->whereIN('coupon_type', (string)$type)->where('maxprice', $mstr, $price)->select()->toArray();
        // halt($coupon, $market);
        // 合并活动券和卡券
        return array_merge($coupon, $market);
    }

    /**
     * 领取卡券
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-27
     */
    public function deriveCoupon($id)
    {
        if (!$id) throw new LogicException('参数错误');

        $coupon = $this->canDerive($id)->findOrEmpty();
        if ($coupon->isEmpty()) throw new LogicException('卡券已领完');

        $mid = request()->mid;
        // 检查用户已领取
        $has = app(CouponUser::class)->where('user_id', $mid)->where('coupon_id', $id)->findOrEmpty();

        if (!$has->isEmpty()) throw new LogicException('你已领取过卡券');

        $this->startTrans();
        try {
            $data['user_id']     = $mid;
            $data['coupon_id']   = $coupon->id;
            $data['mhm_id']      = $coupon->mhm_id;
            $data['coupon_type'] = $coupon->coupon_type;
            $re1                 = CouponUser::create($data);

            $coupon->receive_count += 1;
            $re2                   = $coupon->save();

            if ($re1->isEmpty() || !$re2) {
                throw new LogicException('领取失败');
            }

            $return = $this->findOrEmpty($coupon->id);
            $this->commit();
        } catch (LogicException $e) {
            $this->rollback();
            throw new LogicException($e->getMessage());
        }

        return $return;
    }

    /**
     * 获取用户领取的对应机构卡券列表 - 当前价格条件下可以使用的
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-23
     *
     * @param $mhm_id
     * @param $total_price
     * @return array|Collection|BaseQuery[]
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getUserMhmCouponWithPrice($mhm_id, $total_price)
    {
        $type = request()->device_type == 'pc' ? '1,2' : '1,2,3';

        return $this->hasWhere('couponUser', ['user_id' => request()->mid])->where('coupon_type', 'IN', $type)->where('coupon.mhm_id', '=', $mhm_id)->where('maxprice', '<=', $total_price)->select();
    }

    // 用户可以用的课程卡
    public function userHasDerivedCourseCard($course_id): int
    {
        $coupon = $this->alias('c')->join('coupon_user u', 'u.coupon_id=c.id AND u.status=0 AND u.user_id=' . request()->mid)->where('course_id', $course_id)->where('use_stime', '<', time())->where('use_etime', '>', time())->whereNull('c.delete_time')->findOrEmpty();

        return $coupon->isEmpty() ? 0 : 1;
    }

    // 使用课程卡直接兑换课程
    public function exchangeCourseCard($param)
    {
        // 检测数据
        $this->getValidate()->scene('exchange')->failException()->check($param);
        // 检测课程卡
        $coupon_id = $param['id'];
        $user_id   = request()->mid;
        // 卡券课程
        $coupon = $this->with(['course_solo'])->findOrEmpty($coupon_id);
        // 课程单卖
        if (!$coupon->solo) throw new LogicException('课程已禁用.');
        // 卡券已失效
        if ($coupon->isEmpty() || $coupon->use_etime < time() || $coupon->delete_time) {
            throw new LogicException('卡券已失效');
        }
        if ($coupon->use_stime > time()) throw new LogicException('卡券暂不能使用');
        // 用户已有课程
        $course_id = $coupon->course_id;
        $exist     = app(CourseStudent::class)->where('user_id', $user_id)->where('course_id', $course_id)->findOrEmpty();
        // 用户已支付拼团
        $tuan = app(POI::class)->alias('item')->join('payment_order order', "order.order_no=item.order_no AND order.status=80 AND item.user_id=$user_id")->where('product_id', $course_id)->findOrEmpty();

        if (!$exist->isEmpty() || !$tuan->isEmpty()) throw new LogicException('你已购买此课程，无需重复购买');
        // 用户卡券
        $card = app(CouponUser::class)->where('user_id', $user_id)->where('coupon_id', $coupon_id)->findOrEmpty();
        if ($card->isEmpty()) throw new LogicException('卡券信息错误');
        if ($card->status) throw new LogicException('卡券已使用');
        // 兑换
        $this->startTrans();
        try {
            // 更新卡券状态
            $card->status = 1;
            if (!$card->save()) throw new LogicException('兑换失败');
            // 添加课程学员
            $stu = CourseStudent::create([
                'user_id'   => $user_id,
                'course_id' => $course_id,
                'from'      => 6,
            ]);

            if ($stu->isEmpty()) throw new LogicException('兑换失败');
            // 生成订单
            $this->createOrder($course_id, $coupon_id);

            $this->commit();
        } catch (LogicException|Exception $e) {
            $this->rollback();
            throw new LogicException($e->getMessage());
        }
    }

    protected function createOrder($course_id, $coupon_id)
    {
        // 参数
        $mid  = request()->mid;
        $from = strtolower(request()->device_type);
        $PD   = app(SnowFlake::class)->createPD();
        $PI   = app(SnowFlake::class)->createPI();
        // 课程信息
        $course = app(Course::class)->findOrEmpty($course_id);
        // 主订单
        $order = PO::create([
            'order_no'   => $PD,
            'user_id'    => $mid,
            'from'       => $from,
            'mhm_id'     => request()->user->mhm_id,
            'payment'    => 0,
            'status'     => '20',
            'close_time' => time() + 30 * 60,
        ]);

        if ($order->isEmpty()) throw new LogicException('兑换失败');
        // 生成子订单
        $order_item = POI::create([
            'order_no'        => $PD,
            'order_sub_no'    => $PI,
            'user_id'         => $mid,
            'from'            => $from,
            'mhm_id'          => $course->mhm_id,
            'product_id'      => $course_id,
            'product_type_id' => Course::getProductIdByCourseType($course->course_type),
            'payment'         => 0,
            'original_price'  => $course->price,
            'expire_time'     => time() + $course->term_time * 86400,
        ]);

        if ($order_item->isEmpty()) throw new LogicException('兑换失败');
        // 卡券使用到订单
        $coupon_order = POIC::create(['order_sub_no' => $PI, 'coupon_id' => $coupon_id]);
        if ($coupon_order->isEmpty()) throw new LogicException('兑换失败');
    }

    /* 暂未使用 */

    /**
     * 获取最优卡券 - 针对机构及当前商品总价计算
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-23
     */
    // public function getBestCoupon($mhm_id, $total_price, $obj = false)
    // {
    //     // 优惠券
    //     $re1 = $this->cartMhmCoupon($mhm_id, $total_price, 1)->orderPrice('DESC')->findOrEmpty();
    //     // 打折卡
    //     $re2 = $this->cartMhmCoupon($mhm_id, $total_price, 2)->findOrEmpty();
    //     // 比较最优
    //     if ( !$re1->isEmpty() && !$re2->isEmpty() ) {
    //         $price = $re2->discount * $total_price / 10;
    //         return $price > $re1->price ? $re2 : $re1;
    //     } elseif( $re1->isEmpty() && $re2->isEmpty() && $obj) {
    //         return new \ArrayObject();
    //     } else {
    //         return $re1->isEmpty() ? $re2 : $re1;
    //     }
    // }

    /**
     * 获取购物车卡券列表 - 推荐最优卡券及其他卡券
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-23
     *
     * @param    [type]     $mhm_id      [机构ID]
     * @param    [type]     $total_price [满减价格]
     */
    // public function getCouponAfterBest($mhm_id, $total_price)
    // {
    //     $best = $this->getBestCoupon($mhm_id, $total_price);

    //     if (!$best->isEmpty()) {
    //         $list = $this->cartMhmCoupon($mhm_id, $total_price, '1,2')->where('id', '<>', $best->id)->select();
    //     } else {
    //         $list = $this->cartMhmCoupon($mhm_id, $total_price, '1,2')->select();
    //         $best = new \ArrayObject();
    //     }

    //     return ['best'=>$best, 'list'=>$list];;
    // }

    /**
     * 计算卡券优惠价格
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-24
     *
     * @param integer $type       [卡券类型]
     * @param string  $coupon_ids [卡券IDs]
     * @param string  $course_ids [课程IDs]
     * @return   [type]                 [优惠价格]
     */
    // public function calculateCouponPrice($type = 1, $coupon_ids = '', $course_ids = '')
    // {
    //     switch ($type) {
    //         case 2:
    //             return $this->discountPrice($coupon_ids, $course_ids);
    //             break;
    //         case 3:
    //             return $this->cardPrice($coupon_ids, $course_ids);
    //             break;
    //         default:
    //             return $this->couponPrice($coupon_ids);
    //             break;
    //     }
    // }

    // // 优惠券优惠价格
    // protected function couponPrice($coupon_ids)
    // {
    //     $coupon_price = $this->where('coupon_type', 1)->where('id', 'IN', $coupon_ids)->sum('price');
    //     return $coupon_price;
    // }

    // // 打折卡优惠价格
    // protected function discountPrice($coupon_ids, $course_ids)
    // {
    //     $discount_price = 0;
    //     $discounts      = $this->where('coupon_type', 2)->where('id', 'IN', $coupon_ids)->select();
    //     foreach ($discounts as $discount) {
    //         $price           = app(Course::class)->where('mhm_id', $discount['mhm_id'])->where('id', 'IN', $course_ids)->sum('price');
    //         $discount_price += $price*$discount['discount']/10;
    //     }
    //     return $discount_price;
    // }

    // // 课程卡优惠价格
    // protected function cardPrice($coupon_ids, $course_ids)
    // {
    //     $card_price = app(Course::class)->withJoin('coupon')
    //     ->where('coupon.coupon_type', 3)
    //     ->where('coupon.id', 'IN', $coupon_ids)
    //     ->where('course.id', 'IN', $course_ids)
    //     ->sum('course.price');
    //     return $card_price;
    // }
    /* 暂未使用 */

}
